package solver;

import java.util.Properties;
import java.util.Random;
import model.Problem;
import model.Solution;

public class FlexDeluge extends BaseHeuristicSolver{
	
	double B;
	double Bfactor=0.005; // Allow 1% worst moves
	double kf=0.0; //It behaves like GreatDeluge
	
	static int ALLOW_ONLY_IMPROVE=60;
	static int MAX_NO_IMPROVEMENT_ITERATIONS = 5000;
	static int UPDATE_B_ITERATION = MAX_NO_IMPROVEMENT_ITERATIONS-1;
	
	int maxCost, maxAcceptedCost;
	
	public FlexDeluge(Problem problem,
			Solution initial_solution, Solution current_solution, double Bfactor, double kf) {
		super(problem, initial_solution, current_solution);
		this.Bfactor = Bfactor;
		this.kf = kf;
		name = "FD";
	}
	
	public FlexDeluge(Problem problem,
			Solution initial_solution, Solution current_solution) {
		super(problem, initial_solution, current_solution);
		name = "FD";
	}
	
	public FlexDeluge(Problem problem,
			Solution initial_solution) {
		super(problem, initial_solution);
		name = "FD";
	}
	
	@Override
	public int solveWithTimeLimit(int solution_time) {
		MAX_SOLUTION_TIME = solution_time;
		startSolution();
		reset();
		long c = ALLOW_ONLY_IMPROVE;
		boolean allow_inferior = true;
		boolean decrTBf=true;	
		
		
		while (shouldStop()) {
			if (!makeNextMove())
				continue;
			iterations++;

			// checking the acceptance condition
			if (potential_cost < current_cost) 
			{ // accepting the move
				if (saveCurrentToBest()) {
					// System.out.printf("%d:Better cost found %d from %d\n",
					// iterations, potential_cost,
					// best_cost);
					reset();
					decrTBf=true;
					finishIteration(true, true);
				}
				else
					finishIteration(true, false);
				current_cost = potential_cost;
//				finishIteration(true, true);
			}
			else 
			{// Check inferior or equal solution
//				c--;
//				if (c <= 0) 
//					allow_inferior = true;
//				double delta = potential_cost-best_cost;
//				if ((allow_inferior) && potential_cost <= B) 
				if (potential_cost <= B)
				{// accepting the move but it is inferior
//					if(delta!=0.0){
//						c = ALLOW_ONLY_IMPROVE;
//						allow_inferior = false;
//					}
					finishIteration(true, false);
					current_cost = potential_cost;
				} else 
				{// not accepting the move
					finishIteration(false, false);
				}
				updateB(decrTBf);
			}
			
			// each 100000 steps we output the current and the best costs
			if ((iterations % 100000) == 0) 										
			{
				 System.out.printf(
				 "%10d current (%d) best (%d) noImprovement=%d B=%f\n",
				 iterations, current_cost, best_cost, noImprove, B);
			}
		}//while

		finishSolution(true);
		
		return chrono.getElapsedTimeInSeconds();
	}

	public void reset() {
		B = best_cost*(1+Bfactor);//Start at 1% worse
	}
	
	private void updateB(boolean decrTBf){
		if(noImprove%MAX_NO_IMPROVEMENT_ITERATIONS==UPDATE_B_ITERATION){
			double tbf;
			if (decrTBf && best_cost<B){
				tbf = Math.max(Bfactor/10.0,Bfactor*(1-(noImprove/MAX_NO_IMPROVEMENT_ITERATIONS)));
				B-=tbf*B;
				if(B<best_cost){
					B=best_cost;
					decrTBf=false;
				}
			}
			else{
				decrTBf = false;
				tbf = Math.min(10*Bfactor,Bfactor*(1+(noImprove/(double)MAX_NO_IMPROVEMENT_ITERATIONS)));
				if(tbf==10*Bfactor)
					decrTBf = true;
				B=best_cost*(1+tbf);							
			}
		}
	}
	
	@Override
	public void setBestSolution(Solution newSol){
		super.setBestSolution(newSol);
		reset();
	}

}
